package ar.edu.unq.tpi.uis.tepe3.dominio.persistence;

import ar.edu.unq.tpi.uis.tepe3.dominio.Grantable;
import ar.edu.unq.tpi.uis.tepe3.dominio.Group;
import ar.edu.unq.tpi.uis.tepe3.dominio.SvnManager;
import ar.edu.unq.tpi.uis.tepe3.dominio.User;
import ar.edu.unq.tpi.uis.tepe3.dominio.exception.PersistenceException;

import com.db4o.Db4oEmbedded;
import com.db4o.EmbeddedObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.config.EmbeddedConfiguration;
import com.db4o.constraints.UniqueFieldValueConstraint;
import com.db4o.constraints.UniqueFieldValueConstraintViolationException;
import com.db4o.query.Predicate;

public class Db4oPersistence{

	private static final String PERSISTENCE_DB4O_FILE = "/tmp/Tepe3Persistence.db4o";
	
	private static Db4oPersistence instance = null;
	private EmbeddedObjectContainer db;
	
	/**
	 * Solo para que no funcione en Singleton
	 */
	private Db4oPersistence() {}
	
	public static synchronized Db4oPersistence getInstance(){
		if( instance == null ){
			instance = initialize();
		}
		return instance;
	}

	
	private static Db4oPersistence initialize(){
		instance = new Db4oPersistence();		
		
		connect();
				
		return instance;
	}


	private static void connect() {
		EmbeddedConfiguration conf = Db4oEmbedded.newConfiguration();
		conf.common().updateDepth(10);
		// Defino las claves unicas
		conf.common().objectClass(Grantable.class).objectField("id").indexed(true);
		conf.common().objectClass(Group.class).objectField("id").indexed(true);
		conf.common().objectClass(User.class).objectField("id").indexed(true);
		
		conf.common().add(new UniqueFieldValueConstraint(Grantable.class,"id"));
		conf.common().add(new UniqueFieldValueConstraint(Group.class,"id"));
		conf.common().add(new UniqueFieldValueConstraint(User.class,"id"));
		instance.db = Db4oEmbedded.openFile(conf, PERSISTENCE_DB4O_FILE);
	}
	
	public void close(){
		this.db.close();
	}
	
	public void reconnect(){
		this.db.close();
		Db4oPersistence.connect();
	}
	
	public void store(SvnManager aSvnManager) throws PersistenceException{
		try{
			this.db.store(aSvnManager);
			this.db.commit();
		}catch(UniqueFieldValueConstraintViolationException e) {
			this.db.rollback();
			throw new PersistenceException("Clave unica repetida - " + e.getMessage());
		}
	}
	
	/**
	 * Es solo un alias de store por que me gusta mas "save" que "store".
	 * 
	 * @param aSvnManager
	 * @throws PersistenceException 
	 * @see Db4oPersistence.store()
	 */
	public void save(SvnManager aSvnManager) throws PersistenceException{
		this.store(aSvnManager);
	}
	
	public void delete(SvnManager aSvnManager){
		this.db.delete(aSvnManager);
		this.db.commit();
	}

	// **********************************
	// ** Querys
	// **********************************
	
	public ObjectSet<SvnManager> query(Predicate<SvnManager> predicate){
		return this.db.query(predicate);
	}
	
	public ObjectSet<SvnManager> fetchAll(){
		return this.query(new Predicate<SvnManager>() {

			@Override
			public boolean match(SvnManager arg0) {

				return true;
			}
		});
	}
	
}
